﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommonLib;

namespace TrackingClient
{
    public enum enumHeader
    {
        FromServer = 0x4040,
        FromTracking = 0x2424
    }

    public enum enumCommand
    {
        Server_Confirms_Tracker_Login = 0x4000,
        Tracker_Login = 0x5000
        //Server_Confirms_tracker_login = 16384, //0x4000
        //Tracker_login = 20480 //0x5000
    }

    public class PacketProtocol
    {
        public byte[] _header = new byte[2]; //2 bytes
        public byte[] _length = new byte[2]; //2 bytes
        public byte[] _id = new byte[7]; //7 bytes
        public byte[] _command = new byte[2]; //2 bytes
        public byte[] _data = new byte[100]; //100 bytes
        public byte[] _checksum = new byte[2]; //2 bytes
        public byte[] _end = new byte[2];

        public PacketProtocol()
        {
            
        }

        /// <summary>
        /// Tính checksum
        /// </summary>
        /// <returns></returns>
        public byte[] CalculateCheckSum()
        {
            byte[] allbytes = new byte[13];
            //tạo danh sách các bytes của packet
            _header.CopyTo(allbytes, 0);
            _length.CopyTo(allbytes, _header.Length);
            _id.CopyTo(allbytes, _header.Length + _length.Length);
            _command.CopyTo(allbytes, _header.Length + _length.Length + _id.Length);

            // lenght of all bytes for the packet
            _length = BitConverter.GetBytes((ushort)(_header.Length + _length.Length + _id.Length + _command.Length + _data.Length )); //+objPacket._data

            CRC16CCITT objCrc = new CRC16CCITT();
            objCrc.Crc16Ccitt(InitialCrcValue.NonZero1);
            _checksum = objCrc.ComputeChecksumBytes(allbytes);

            return _checksum;
        }

        #region My Custom Protocol

        /// <summary>
        /// Tạo packet protocol
        /// Protocol: <$$ (2 bytes)><L ( 2 bytes )><ID (7 bytes)><command (2 bytes)><data (160 bytes)><checksum (2 bytes)><\r\n (2 bytes)>
        /// </summary>
        /// <returns></returns>
        public byte[] CreateFullPacket()
        {
            //Lưu độ dài byte hiện tại
            int len = 0;

            //Tạo danh sách các bytes của packet
            _length = BitConverter.GetBytes((ushort)(_header.Length + _length.Length + _id.Length + _command.Length + _data.Length + _checksum.Length + _end.Length));

            //Khởi tạo packet có kích thước là _length
            byte[] packet = new byte[BitConverter.ToInt16(_length, 0)];

            //khởi tạo biến lưu packet dùng để tính checksum
            //checksum chỉ tính các byte của các _header, _length, _id, _command, _data (không tính các byte của _checksum)
            int checkSumLen = _header.Length + _length.Length + _id.Length + _command.Length + _data.Length;
            byte[] checkSumPacket = new byte[checkSumLen];

            //$$ : header
            _header.CopyTo(packet, 0);
            _header.CopyTo(checkSumPacket, 0);
            len += _header.Length;

            //<L> : lenght of all bytes for the packet
            _length.CopyTo(packet, len);
            _length.CopyTo(checkSumPacket, len);
            len += _length.Length;

            //<ID (7 bytes)>
            _id.CopyTo(packet, len);
            _id.CopyTo(checkSumPacket, len);
            len += _id.Length;

            //<command (2 bytes)>
            _command.CopyTo(packet, len);
            _command.CopyTo(checkSumPacket, len);
            len += _command.Length;

            //<data>
            if (_data.Length > 0)
            {
                _data.CopyTo(packet, len);
                _data.CopyTo(checkSumPacket, len);
                len += _data.Length;
            }

            //<checksum (2 bytes)>
            //calculate checksum by Crc16citt method
            CRC16CCITT objCrc = new CRC16CCITT();
            objCrc.Crc16Ccitt(InitialCrcValue.NonZero1);
            _checksum = objCrc.ComputeChecksumBytes(checkSumPacket);
            _checksum.CopyTo(packet, len);
            len += _checksum.Length;

            _end.CopyTo(packet, len);

            return packet;
        }

        /// <summary>
        /// Create a packet for client send to server
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public byte[] CreateSendingProtocol(byte[] data)
        {
            //PacketProtocol objPacket = new PacketProtocol();

            // header for packet from tracking unit to server

            _header = BitConverter.GetBytes((Int16)enumHeader.FromTracking);//new byte[] { 0x24, 0x24 };

            //id in hex code: 13612345678, unused bytes is 'f' or '0xff'
            _id = new byte[] { 0x13, 0x61, 0x23, 0x45, 0x67, 0x8f, 0xff };

            //command Tradker's login: 0x5000
            _command = BitConverter.GetBytes((ushort)enumCommand.Tracker_Login); ; // new byte[] { 0x00, 0x50 };

            //data
            if (data.Length > 0)
            {
                _data = new byte[data.Length];
                data.CopyTo(_data, 0);
            }

            //get end characters
            _end = new byte[] { 0x0d, 0x0a }; //Encoding.ASCII.GetBytes("\r\n");

            byte[] packet = CreateFullPacket();
            return packet;
        }

        #endregion

        public string PrintHexBytes(byte[] bytes)
        {
            string strHex = "";
            if ((bytes == null) || (bytes.Length == 0))
                strHex = "<none>";
            else
            {
                for (int i = 0; i < bytes.Length; i++)
                    strHex += string.Format("{0:X2} ", bytes[i]);
            }
            return strHex;
        }
    }

}
